<template>
    <div class="chart trade-view-comp cont-box">
        <div id="trade-view-root"></div>
        <div class="loading-box" v-if="chartLoading">
            <van-loading type="spinner"></van-loading>
        </div>
    </div>
</template>

<script setup>
import { ref, computed, onMounted, onBeforeUnmount } from 'vue';
import { init, dispose } from 'klinecharts'
import { useMit } from '@/hooks/useEventBus'
import config from '@/components/Kline/config'
import { inflate } from 'pako';
const WS_URL = import.meta.env.VITE_APP_WS;

let chart = null
const props = defineProps(['type'])



const chartLoading = ref(true)
const symbol = ref('')
function tradingViewInit(code, interval) {
    symbol.value = code

    chart = init('trade-view-root', config)
    chart.setOffsetRightSpace(0)
    chart.createTechnicalIndicator('MA', false, { id: 'candle_pane' });
    chart.createTechnicalIndicator('VOL');
    // chart.setPriceVolumePrecision(6, 5)
    fetchData(interval)
}

const interval = ref('')
async function fetchData(Interval) {
    interval.value = Interval
    if (Interval == 'deep') {
        Interval = '1'
    }
    chartLoading.value = true
    let to = new Date().getTime()
    let from = getInterval.value
    let res = await reqKlinHistory(
        symbol.value,
        Interval,
        from / 1000,
        to / 1000
    );
    chartLoading.value = false
    let bars = []
    let meta = { noData: false }
    if (res.data.length < 1) {
        meta.noData = true;
        meta.nextTime = res.nextTime; // 如果没有数据，应该有nextTime
    } else {
        // console.log(JSON.parse(res.data[res.data.length - 1]).time);
        // console.log(res.data);

        res.data.forEach((e) => {
            let obj = JSON.parse(e);
            const { high, low } = obj;
            // console.log(obj);

            if (high && low) {
                bars.push({
                    open: obj.open,
                    close: obj.close,
                    high: obj.high,
                    low: obj.low,
                    volume: obj.volume || obj.vol,
                    timestamp: obj.time - 0,
                });
            }
        });

    }
    setChartType()
    chart.applyNewData(bars);
    subscribeBars(Interval)
}

const getInterval = computed(() => {
    let Interval = interval.value
    if (Interval == 'deep') {
        Interval = '1'
    }
    let to = new Date().getTime()
    const day = 1000 * 60 * 60 * 24
    let from = NaN
    switch (Interval) {
        case '1': { // 1分钟获取1周
            let minus = day * 7 // 1周
            from = to - minus
        }
            break;
        case '5': { // 5分钟获取1周
            let minus = day * 7 // 1周
            from = to - minus
        }
            break;
        case '15': { // 15分钟获取2周
            let minus = day * 15 // 2周
            from = to - minus
        }
            break;
        case '30': { // 60分钟获取2周
            let minus = day * 14 // 2周
            from = to - minus
        }
            break;
        case '60': { // 60分钟获取2周
            let minus = day * 14 // 2周
            from = to - minus
        }
            break;
        case 'D': { // 1D获取3月
            let minus = day * 90 // 3月
            from = to - minus
        }
            break;
        case 'W': { // 1W获取1年
            let minus = day * 365 // 1年
            from = to - minus
        }
            break;
        default:
            break;
    }
    return from
})
function subscribeBars(Interval) {

}

function setChartType() {
    let type = 'area'
    if (interval.value == 'deep') {
        type = 'area'
    } else {
        type = 'candle_solid'
    }
    chart.setStyleOptions({
        candle: {
            type
        }
    })
}




// wsBus
const promiseBreaker = () => {
    let resolve, reject;
    let promise = new Promise((s, j) => {
        // eslint-disable-line
        resolve = s;
        reject = j;
        setTimeout(reject, 15 * 1000, "pending time up");
    });
    return Object.assign(promise, { resolve, reject });
};

function unzip(b64Data) {
    let strData = atob(b64Data);
    const charData = strData.split('').map(function (x) {
        return x.charCodeAt(0);
    })
    const binData = new Uint8Array(charData);
    const data = inflate(binData);
    const array = new Uint8Array(data);
    let res = '';
    const chunk = 8 * 1024
    var i;
    for (i = 0; i < array.length / chunk; i++) {
        res += String.fromCharCode.apply(null, array.slice(i * chunk, (i + 1) * chunk));
    }
    res += String.fromCharCode.apply(null, array.slice(i * chunk));

    strData = res
    return strData;
}

const connectReady = ref(promiseBreaker())
const wsRef = ref(null)
// init
function initWs(params) {
    let ws = (wsRef.value = new WebSocket(WS_URL))
    ws.onopen = () => {
        connectReady.value.resolve()
    }
    ws.onmessage = (ev) => {
        const blob = ev.data
        if (typeof blob == "string") {
            return;
        }
        const newBlob = blob.slice(0, blob.size)
        const reader = new FileReader()
        reader.readAsBinaryString(newBlob)
        reader.onload = (evt) => {
            if (evt.target.readyState == FileReader.DONE) {
                const zipdata = unzip(evt.target.result)
                // console.log('zipdata ===>',zipdata);
                // JSON 能解析  k 线数据

                const msg = JSON.parse(zipdata);
                // console.log("msg ===>", msg);

                if (msg && msg.data.length != 0) {


                    if (msg.method && msg.method === "oneKline") {
                        // console.log("oneKline ===>", msg);
                        // 更新kline
                        // this.$emit("subscribeBar", msg);
                        const { data } = msg;
                        // emit("fromRandomCurrentPrice", {
                        //     close: msg.close,
                        //     higPrice: msg.high24,
                        //     lowPrice: msg.low24,
                        //     volume: msg.volume24,
                        //     updown: msg.updown,
                        // });
                    } else if (msg.method && msg.method === "initKline") {
                        // console.log("initKline ===>", msg)
                        useMit.emit("klineHistoryData", msg)
                    }

                }
            }
        }
    }
    ws.onclose = () => {
        connectReady.value = promiseBreaker()
        initWs()
    }
    ws.onerror = () => {
        initWs()
    }
}


const timer = ref(null)
// doClose
function doClose() {
    if (timer.value !== null) {
        clearInterval(timer.value)
    }
    wsRef.value.close()
}

const from = ref(0)
const period = ref('')
const firstReq = ref(true)

// 请求k线历史数据
async function reqKlinHistory(code, resolution, fromTime, toTime) {
    await connectReady.value
    from.value = from
    if (resolution > 0 && resolution < 60) {
        period.value = resolution + "min";
    } else if (resolution == 60) {
        period.value = "60min";
    } else if (resolution == "D") {
        period.value = "1d";
    } else if (resolution == "W") {
        period.value = "1week";
    }

    const res = await new Promise((resolve, reject) => {
        useMit.on('klineHistoryData', (msg) => {
            if (firstReq.value) {
                resolve(msg)
                firstReq.value = false
            }
        })

        wsRef.value.send('PING')
        clearInterval(timer.value)
        timer.value = setInterval(() => {
            wsRef.value.send('PING')
        }, 5000)
        const str = `initKline-${code}-${period.value}-${fromTime * 1000}-${toTime * 1000}`
        wsRef.value.send(str)
    })
    return res
}



onMounted(() => {
    tradingViewInit('BTC/USDT', '15')
    initWs()
})



onBeforeUnmount(() => {
    doClose()
    firstReq.value = true
    useMit.off('klineHistoryData')
    dispose('trade-view-root')
})
defineExpose({
    chartLoading,
    promiseBreaker,
    tradingViewInit,
})
</script>

<style lang="less" scoped>
.trade-view-comp {
    position: relative;
}

/* flex justify-center items-center text-center text-grey absolute left-0 top-0  w-full h-full z-10 mainBackground */
.loading-box {
    display: flex;
    justify-content: center;
    align-items: center;
    text-align: center;
    color: grey;
    position: absolute;
    left: 0;
    top: 0;
    width: 100%;
    height: 100%;
    z-index: 10;

}

#trade-view-root {
    width: 100vw;
    height: 100vh;
}
</style>